// Copyright 2021 Guoyoko. All Rights Reserved.

#include "Toolkits/CustomizeFlowEditorToolkit.h"
#include "Asset/CustomizeFlowAsset.h"
#include "Framework/Commands/GenericCommands.h"
#include "GraphEditorActions.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "EditorStyleSet.h"
#include "Graph/CustomizeFlowGraphSchema.h"
#include "Graph/CustomizeFlowGraph.h"
#include "Graph\CustomizeFlowGraphNode.h"


#define LOCTEXT_NAMESPACE "FCustomizeFlowEditorToolkit"

/* Local constants
 *****************************************************************************/

const FName SelfAssetEditorAppName = FName(TEXT("CustomizeFlowEditorApp"));

namespace FCustomizeFlowEditorTabs
{
	// Tab identifiers
	static const FName PropertyID("CustomizeFlowEditorProperty");
	static const FName ViewportID("Viewport");
};

void FCustomizeFlowEditorToolkit::Initialize(const EToolkitMode::Type InMode, const TSharedPtr<IToolkitHost>& InToolkitHost, UObject* InAsset)
{
	CustomizeFlowAsset = Cast<UCustomizeFlowAsset>(InAsset);

	FGenericCommands::Register();
	FGraphEditorCommands::Register();

	CreateEdGraph();

	ViewportWidget = CreateViewportWidget(CustomizeFlowAsset);
	DetailWidget = CreateDetailWidget(CustomizeFlowAsset);
	DetailWidget->SetObject(CustomizeFlowAsset);

	// create tab layout
	const TSharedRef<FTabManager::FLayout> Layout = FTabManager::NewLayout("Standalone_CustomizeFlowEditor")
		->AddArea
		(
			FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
			->Split
			(
				FTabManager::NewStack()
				->AddTab(GetToolbarTabId(), ETabState::OpenedTab)->SetHideTabWell(true)
			)
			->Split
			(
				FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)->SetSizeCoefficient(0.9f)
				->Split
				(
					FTabManager::NewStack()
					->SetSizeCoefficient(0.8f)
					->AddTab(FCustomizeFlowEditorTabs::ViewportID, ETabState::OpenedTab)->SetHideTabWell(true)
				)
				->Split
				(
					FTabManager::NewStack()
					->SetSizeCoefficient(0.2f)
					->AddTab(FCustomizeFlowEditorTabs::PropertyID, ETabState::OpenedTab)->SetHideTabWell(true)
				)
			)
		);

	FAssetEditorToolkit::InitAssetEditor(
		InMode,
		InToolkitHost,
		SelfAssetEditorAppName,
		Layout,
		true /*bCreateDefaultStandaloneMenu*/,
		true /*bCreateDefaultToolbar*/,
		InAsset
	);

	RegenerateMenusAndToolbars();
}

/* FAssetEditorToolkit interface
 *****************************************************************************/

void FCustomizeFlowEditorToolkit::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
{
	WorkspaceMenuCategory = InTabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_SelfAssetEditor", "Self Asset Editor"));
	auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();

	FAssetEditorToolkit::RegisterTabSpawners(InTabManager);

	InTabManager->RegisterTabSpawner(FCustomizeFlowEditorTabs::ViewportID, FOnSpawnTab::CreateSP(this, &FCustomizeFlowEditorToolkit::SpawnTab_Viewport));
	InTabManager->RegisterTabSpawner(FCustomizeFlowEditorTabs::PropertyID, FOnSpawnTab::CreateSP(this, &FCustomizeFlowEditorToolkit::SpawnTab_Details));
}

void FCustomizeFlowEditorToolkit::UnregisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
{
	FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);

	InTabManager->UnregisterTabSpawner(FCustomizeFlowEditorTabs::ViewportID);
	InTabManager->UnregisterTabSpawner(FCustomizeFlowEditorTabs::PropertyID);
}


/* IToolkit interface
 *****************************************************************************/

FText FCustomizeFlowEditorToolkit::GetBaseToolkitName() const
{
	return LOCTEXT("AppLabel", "Customize Flow Editor");
}

FName FCustomizeFlowEditorToolkit::GetToolkitFName() const
{
	return FName("CustomizeFlowEditor");
}

FLinearColor FCustomizeFlowEditorToolkit::GetWorldCentricTabColorScale() const
{
	return FLinearColor(0.3f, 0.2f, 0.5f, 0.5f);
}

FString FCustomizeFlowEditorToolkit::GetWorldCentricTabPrefix() const
{
	return LOCTEXT("WorldCentricTabPrefix", "CustomizeFlowAsset ").ToString();
}

/* FGCObject interface
 *****************************************************************************/

void FCustomizeFlowEditorToolkit::AddReferencedObjects(FReferenceCollector& Collector)
{
	Collector.AddReferencedObject(CustomizeFlowAsset);
}

/* FCustomizeFlowEditorToolkit callbacks
 *****************************************************************************/

TSharedRef<SDockTab> FCustomizeFlowEditorToolkit::SpawnTab_Viewport(const FSpawnTabArgs& Args)
{
	check(Args.GetTabId() == FCustomizeFlowEditorTabs::ViewportID);

	return SNew(SDockTab)
		.TabRole(ETabRole::PanelTab)
		[
			ViewportWidget.ToSharedRef()
		];
}


TSharedRef<SDockTab> FCustomizeFlowEditorToolkit::SpawnTab_Details(const FSpawnTabArgs& Args)
{
	check(Args.GetTabId() == FCustomizeFlowEditorTabs::PropertyID);

	return SNew(SDockTab)
		.Icon(FEditorStyle::GetBrush("LevelEditor.Tabs.Details"))
		.Label(LOCTEXT("Details_Title", "Property"))
		[
			DetailWidget.ToSharedRef()
		];
}

TSharedRef<SGraphEditor> FCustomizeFlowEditorToolkit::CreateViewportWidget(UCustomizeFlowAsset* Graph)
{
	FGraphAppearanceInfo AppearanceInfo;
	AppearanceInfo.CornerText = FText::FromString(Graph->GetName());
	TSharedPtr<FUICommandList> GraphEditorCommands;


	SGraphEditor::FGraphEditorEvents InEvents;
	InEvents.OnNodeDoubleClicked = FSingleNodeEvent::CreateSP(this, &FCustomizeFlowEditorToolkit::OnNodeDoubleClicked);

	return SNew(SGraphEditor)
		.AdditionalCommands(GraphEditorCommands)
		.IsEditable(true)
		.Appearance(AppearanceInfo)
		.GraphToEdit(CustomizeFlowAsset->EdGraph)
		.GraphEvents(InEvents)
		.AutoExpandActionMenu(true)
		.ShowGraphStateOverlay(false);
}

TSharedRef<IDetailsView> FCustomizeFlowEditorToolkit::CreateDetailWidget(UCustomizeFlowAsset* Graph)
{
	FDetailsViewArgs DetailsViewArgs(
		/*bUpdateFromSelection=*/ false,
		/*bLockable=*/ false,
		/*bAllowSearch=*/ false,
		FDetailsViewArgs::HideNameArea,
		/*bHideSelectionTip=*/ true,
		/*InNotifyHook=*/ nullptr,
		/*InSearchInitialKeyFocus=*/ false,
		/*InViewIdentifier=*/ NAME_None);
	FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
	return PropertyModule.CreateDetailView(DetailsViewArgs);
}

void FCustomizeFlowEditorToolkit::CreateEdGraph()
{
	if (CustomizeFlowAsset->EdGraph == nullptr)
	{
		CustomizeFlowAsset->EdGraph = CastChecked<UCustomizeFlowGraph>(
			FBlueprintEditorUtils::CreateNewGraph(CustomizeFlowAsset, NAME_None,
				UCustomizeFlowGraph::StaticClass(), UCustomizeFlowGraphSchema::StaticClass()));
		CustomizeFlowAsset->EdGraph->bAllowDeletion = true;

		const UEdGraphSchema* Schema = CustomizeFlowAsset->EdGraph->GetSchema();
		Schema->CreateDefaultNodesForGraph(*CustomizeFlowAsset->EdGraph);
	}
}

void FCustomizeFlowEditorToolkit::OnNodeDoubleClicked(class UEdGraphNode* Node)
{
	UCustomizeFlowGraphNode* MyNode = Cast<UCustomizeFlowGraphNode>(Node);
	if (MyNode && MyNode->NodeInstance)
	{
		UClass* NodeClass = MyNode->NodeInstance->GetClass();
		UPackage* Pkg = NodeClass->GetOuterUPackage();
		FString ClassName = NodeClass->GetName().LeftChop(2);
		UBlueprint* BlueprintOb = FindObject<UBlueprint>(Pkg, *ClassName);
		if (BlueprintOb)
		{
			GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(BlueprintOb);
		}
	}
}

#undef LOCTEXT_NAMESPACE

